package com.edu.learning.utils;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author ll
 * @Date 2017/10/30 15:32
 */
public class LearnThreadFactory implements ThreadFactory {

    private final AtomicLong threadNum = new AtomicLong(1);

    private final String namePrefix;

    private final boolean daemon;

    private static final ThreadGroup threadGroup = new ThreadGroup("Learn");

    public static ThreadGroup getThreadGroup() {
        return threadGroup;
    }

    public static LearnThreadFactory create (String namePrefix, boolean daemon) {
        return new LearnThreadFactory(namePrefix, daemon);
    }

    public static boolean waitAllShutdown(int timeoutInMillis) {
        ThreadGroup group = getThreadGroup();
        Thread[] activeThreads = new Thread[group.activeCount()];
        Set<Thread> alives = new HashSet<Thread>(Arrays.asList(activeThreads));
        Set<Thread> dies = new HashSet<Thread>();

        System.err.println("Current ACTIVE thread count is : {}" + alives.size());

        long expire = System.currentTimeMillis() + timeoutInMillis;
        if (System.currentTimeMillis() < expire) {
            classify (alives, dies, new ClassifyStandard<Thread>() {

                @Override
                public boolean satisfy(Thread thread) {
                    return !thread.isAlive() || thread.isInterrupted() || thread.isDaemon();
                }
            });

            if (alives.size() > 0) {
                System.err.println("Alive learn threads : {}" + alives);
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    //ignore
                }
            } else {
                System.err.println("Alive learn threads : {}" + alives);
                return true;
            }
        }
        System.err.println("some learn threads are still alive but expire time has reached, alive threads : {}" + alives);
        return false;
    }

    /**
     * 满足条件的线程对象
     *
     * @param <T>
     */
    private static interface ClassifyStandard<T> {
        boolean satisfy (T thread);
    }

    private static <T> void classify(Set<T> src, Set<T> des, ClassifyStandard<T> standard) {
        Set<T> set = new HashSet<>();
        for (T t : src) {
            if (standard.satisfy(t)) {
                set.add(t);
            }
        }
        src.removeAll(set);
        des.addAll(set);
    }

    @Override
    public Thread newThread(Runnable runnable) {
        String threadName = threadGroup.getName() + "-" + namePrefix + "-" + threadNum.getAndIncrement();
        Thread thread = new Thread(threadGroup, runnable, threadName);
        thread.setDaemon(daemon);
        if (thread.getPriority() != Thread.NORM_PRIORITY) {
            thread.setPriority(Thread.NORM_PRIORITY);
        }
        return thread;
    }

    public LearnThreadFactory(String namePrefix, boolean daemon) {
        this.namePrefix = namePrefix;
        this.daemon = daemon;
    }
}
